#ifndef DYN_ROOTS_MULTIDIM_NEWTONRAPHSON_H
#define DYN_ROOTS_MULTIDIM_NEWTONRAPHSON_H

#include <armadillo>

#include "../utilities/dyn_multifunctor.h"
#include "dyn_roots.h"

/*! \brief Vector version
 * of Newton-Raphson.
 *
 * It has a very poor
 * global convergence (its attraction basins
 * are incredibly rich), but quadratic local
 * convergence.
 *
 * Although we derive from RootFinding,
 * several functions and member variables
 * are of a different type. We take a
 * vector input and return a vector output.
 */

class MultiDimNewtonRaphson : public RootFinding
{
public:
    /*! The constructor initializes the relevant member variables.*/
    MultiDimNewtonRaphson(MultiFunctor& func,
                          MultiFunctor& jac,
                          vec init,
                          const double tol,
                          const int Nmax);

    /*! @name Accessor functions.
     * Specialized accessor functions for
     * multi-dimensional Newton-Raphson.
     */
    //@{
    MultiFunctor& getFunction() {return m_function;}
    MultiFunctor& getJacobian() {return m_jacobian;}
    vec getm_Root() {return m_root;}
    vec getm_InitialValue() {return m_initialValue;}

    void setFunction(MultiFunctor& func) {m_function = func;}
    void setJacobian(MultiFunctor& jaco) {m_jacobian = jaco;}
    void setInitialValue(vec init) {m_initialValue = init;}
    //@}

    /*! The derived solve() method.
     * Returns 0 if all goes well and any other
     * integer if there is an error. In our case,
     * if it returns 1, failed to converge
     * within maxIterations.
     */
    int solve();

protected:
    /*! @name Specialized member variables.
     * We declare some variables that are not
     * present in the base class, such as the function,
     * the jacobian and define new types for existing variables.
     */
    //@{
    MultiFunctor& m_function;
    MultiFunctor& m_jacobian;
    vec m_root;
    vec m_initialValue;




};

#endif // DYN_ROOTS_MULTIDIM_NEWTONRAPHSON_H
